//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Windows;
using System.Windows.Controls;

namespace OpenLS.Spreadsheet.UI
{
    public class WorksheetPanel: Panel
    {
        public WorksheetPanel()
        {
            HorizontalAlignment = HorizontalAlignment.Stretch;
            VerticalAlignment = VerticalAlignment.Stretch;
        }
        protected override Size ArrangeOverride(Size finalSize)
        {
            double[] widths = new double[5];
            double[] heights = new double[5];
            foreach (FrameworkElement element in InternalChildren)
            {
                Size sz;
                element.InvalidateMeasure();
                sz = element.DesiredSize;
                double? width = GetDesiredWidth(element);
                if (width != null)
                {

                    sz = new Size(width.Value, sz.Height);
                }
                double? height = GetDesiredHeight(element);
                if (height != null)
                    sz = new Size(sz.Width, height.Value);
                int row = GetRow(element);
                int column = GetColumn(element);
                if (row != SecondPaneRow && GetRowSpan(element) == 1 && !GetIgnoreHeight(element))
                    heights[row] = Math.Max(heights[row], sz.Height);
                if (column != SecondPaneColumn && GetColumnSpan(element) == 1 && !GetIgnoreWidth(element))
                {
                    widths[column] = Math.Max(widths[column], sz.Width);
                }
            }
            double w = finalSize.Width; double h = finalSize.Height;
            foreach (double d in widths)
                w =  w - d;
            foreach (double d in heights)
                h = h - d;
            widths[SecondPaneColumn] = w;
            if (w < 0)
            {
                widths[FirstPaneColumn] += w;
                widths[SecondPaneColumn] = 0;
            }
            heights[SecondPaneRow] = h;
            if (h < 0)
            {
                heights[FirstPaneRow] += h;
                heights[SecondPaneRow] = 0;
            }
            double[] xpositions = new double[5];
            double value = 0;
            for (int i = 0; i < widths.Length; i++)
            {
                xpositions[i] = value;
                value += widths[i];
            }
            double[] ypositions = new double[5];
            value = 0;
            for (int i = 0; i < heights.Length; i++)
            {
                ypositions[i] = value;
                value += heights[i];
            }
            foreach (UIElement element in InternalChildren)
            {
                int row = GetRow(element);
                int column = GetColumn(element);
                int rowSpan = GetRowSpan(element);
                int columnSpan = GetColumnSpan(element);
                double width = 0;
                double height = 0;
                for (int i = column; i < column + columnSpan; i++)
                {
                    width += widths[i];
                }
                for (int i = row; i < row + rowSpan; i++)
                {
                    height += heights[i];
                }
                double d = width;
                Contract.Assert(d <= finalSize.Width + 0.000000001);
                Contract.Assert((width >= 0));
                Contract.Assert((height >= 0));
                width = Math.Max(width, 0); // Just in case
                height = Math.Max(height, 0);
                element.Arrange(new Rect(new Point(xpositions[column], ypositions[row]), new Size(width, height)));
            }
            return finalSize;
        }
        protected override Size MeasureOverride(Size availableSize)
        {
            foreach (UIElement element in InternalChildren)
            {
                element.Measure(availableSize);
            }
            var result =  base.MeasureOverride(availableSize);
            return result;
        }



        public static int GetColumnSpan(DependencyObject obj)
        {
            return (int)obj.GetValue(ColumnSpanProperty);
        }

        public static void SetColumnSpan(DependencyObject obj, int value)
        {
            obj.SetValue(ColumnSpanProperty, value);
        }

        // Using a DependencyProperty as the backing store for ColumnSpan.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ColumnSpanProperty =
            DependencyProperty.RegisterAttached("ColumnSpan", typeof(int), typeof(WorksheetPanel), new UIPropertyMetadata(1));



        public static int GetRowSpan(DependencyObject obj)
        {
            return (int)obj.GetValue(RowSpanProperty);
        }

        public static void SetRowSpan(DependencyObject obj, int value)
        {
            obj.SetValue(RowSpanProperty, value);
        }

        // Using a DependencyProperty as the backing store for RowSpan.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RowSpanProperty =
            DependencyProperty.RegisterAttached("RowSpan", typeof(int), typeof(WorksheetPanel), new UIPropertyMetadata(1));



        public static int GetRow(DependencyObject obj)
        {
            return (int)obj.GetValue(RowProperty);
        }

        public static void SetRow(DependencyObject obj, int value)
        {
            obj.SetValue(RowProperty, value);
        }

        // Using a DependencyProperty as the backing store for Row.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RowProperty =
            DependencyProperty.RegisterAttached("Row", typeof(int), typeof(WorksheetPanel), new UIPropertyMetadata(0));



        public static int GetColumn(DependencyObject obj)
        {
            return (int)obj.GetValue(ColumnProperty);
        }

        public static void SetColumn(DependencyObject obj, int value)
        {
            obj.SetValue(ColumnProperty, value);
        }

        // Using a DependencyProperty as the backing store for Column.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ColumnProperty =
            DependencyProperty.RegisterAttached("Column", typeof(int), typeof(WorksheetPanel), new UIPropertyMetadata(0));





        public static double? GetDesiredWidth(DependencyObject obj)
        {
            return (double?)obj.GetValue(DesiredWidthProperty);
        }

        public static void SetDesiredWidth(DependencyObject obj, double? value)
        {
            obj.SetValue(DesiredWidthProperty, value);
        }

        // Using a DependencyProperty as the backing store for DesiredWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DesiredWidthProperty =
            DependencyProperty.RegisterAttached("DesiredWidth", typeof(double?), typeof(WorksheetPanel), new FrameworkPropertyMetadata(null, 
            FrameworkPropertyMetadataOptions.AffectsParentArrange| FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));
        public static double? GetDesiredHeight(DependencyObject obj)
        {
            return (double?)obj.GetValue(DesiredHeightProperty);
        }

        public static void SetDesiredHeight(DependencyObject obj, double? value)
        {
            obj.SetValue(DesiredHeightProperty, value);
        }

        // Using a DependencyProperty as the backing store for DesiredHeight.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DesiredHeightProperty =
            DependencyProperty.RegisterAttached("DesiredHeight", typeof(double?), typeof(WorksheetPanel), new 
                FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsParentArrange | FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));

        public double PaneWidth
        {
            get { return (double)GetValue(PaneWidthProperty); }
            set { SetValue(PaneWidthProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PaneWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PaneWidthProperty =
            DependencyProperty.Register("PaneWidth", typeof(double), typeof(WorksheetPanel), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsArrange));



        public double PaneHeight
        {
            get { return (double)GetValue(PaneHeightProperty); }
            set { SetValue(PaneHeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PaneHeight.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PaneHeightProperty =
            DependencyProperty.Register("PaneHeight", typeof(double), typeof(WorksheetPanel), new FrameworkPropertyMetadata(0.0,FrameworkPropertyMetadataOptions.AffectsArrange));



        public int FirstPaneColumn
        {
            get { return (int)GetValue(FirstPaneColumnProperty); }
            set { SetValue(FirstPaneColumnProperty, value); }
        }

        // Using a DependencyProperty as the backing store for FirstPaneColumn.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FirstPaneColumnProperty =
            DependencyProperty.Register("FirstPaneColumn", typeof(int), typeof(WorksheetPanel), new UIPropertyMetadata(2));

        

        public int FirstPaneRow
        {
            get { return (int)GetValue(FirstPaneRowProperty); }
            set { SetValue(FirstPaneRowProperty, value); }
        }

        // Using a DependencyProperty as the backing store for FirstPaneRow.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FirstPaneRowProperty =
            DependencyProperty.Register("FirstPaneRow", typeof(int), typeof(WorksheetPanel), new UIPropertyMetadata(2));

        

        public int SecondPaneRow
        {
            get { return (int)GetValue(SecondPaneRowProperty); }
            set { SetValue(SecondPaneRowProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PaneRow.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SecondPaneRowProperty =
            DependencyProperty.Register("SecondPaneRow", typeof(int), typeof(WorksheetPanel), new UIPropertyMetadata(0));



        public int SecondPaneColumn
        {
            get { return (int)GetValue(SecondPaneColumnProperty); }
            set { SetValue(SecondPaneColumnProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PaneColumn.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SecondPaneColumnProperty =
            DependencyProperty.Register("SecondPaneColumn", typeof(int), typeof(WorksheetPanel), new UIPropertyMetadata(0));




        public static bool GetIgnoreWidth(DependencyObject obj)
        {
            return (bool)obj.GetValue(IgnoreWidthProperty);
        }

        public static void SetIgnoreWidth(DependencyObject obj, bool value)
        {
            obj.SetValue(IgnoreWidthProperty, value);
        }

        // Using a DependencyProperty as the backing store for IgnoreWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IgnoreWidthProperty =
            DependencyProperty.RegisterAttached("IgnoreWidth", typeof(bool), typeof(WorksheetPanel), new UIPropertyMetadata(false));



        public static bool GetIgnoreHeight(DependencyObject obj)
        {
            return (bool)obj.GetValue(IgnoreHeightProperty);
        }

        public static void SetIgnoreHeight(DependencyObject obj, bool value)
        {
            obj.SetValue(IgnoreHeightProperty, value);
        }

        // Using a DependencyProperty as the backing store for IgnoreHeight.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IgnoreHeightProperty =
            DependencyProperty.RegisterAttached("IgnoreHeight", typeof(bool), typeof(WorksheetPanel), new UIPropertyMetadata(false));


    }
}
